package com.zanfeng.signleplatform.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by weit on 2018/4/30.
 * Email: weit.just2010@gmail.com
 */
public class HttpUtil {

    private static final Logger LOG = LoggerFactory.getLogger(HttpUtil.class);
    public static final int CONNECT_TIMEOUT = 30000;//设置超时毫秒数
    public static final int SOCKET_TIMEOUT = 30000;//设置传输毫秒数
    public static final int REQUESTCONNECT_TIMEOUT = 30000;//获取请求超时毫秒数
    private static final int CONNECT_TOTAL = 200;//最大连接数
    private static final int CONNECT_ROUTE = 20;//设置每个路由的基础连接数
    private static final int VALIDATE_TIME = 30000;//设置重用连接时间
    private static final String RESPONSE_CONTENT = "请求失败";

    private static PoolingHttpClientConnectionManager manager = null;
    private static CloseableHttpClient client = null;

    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");
        // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }
            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sc.init(null, new TrustManager[] { trustManager }, null);
        return sc;
    }

    static {
        SSLContext sslcontext = null;
        try {
            sslcontext = createIgnoreVerifySSL();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("https", new SSLConnectionSocketFactory(sslcontext))
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .build();
        manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

//        ConnectionSocketFactory csf = PlainConnectionSocketFactory.getSocketFactory();
//        LayeredConnectionSocketFactory lsf = createSSLConnSocketFactory();
//        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
//                .register("http", csf).register("https", lsf).build();
//        manager = new PoolingHttpClientConnectionManager(registry);
        manager.setMaxTotal(CONNECT_TOTAL);
        manager.setDefaultMaxPerRoute(CONNECT_ROUTE);
        manager.setValidateAfterInactivity(VALIDATE_TIME);
        SocketConfig config = SocketConfig.custom().setSoTimeout(SOCKET_TIMEOUT).build();
        manager.setDefaultSocketConfig(config);
        RequestConfig requestConf = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT)
                .setConnectionRequestTimeout(REQUESTCONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
        client = HttpClients.custom().setConnectionManager(manager).setDefaultRequestConfig(requestConf).setRetryHandler(new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException e, int i, HttpContext httpContext) {
                return false;
            }
        }).build();
        if (manager != null && manager.getTotalStats() != null)
            LOG.info("客户池状态：" + manager.getTotalStats().toString());
    }

    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        SSLContext context;
        try {
            context = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            sslsf = new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE);
        } catch (NoSuchAlgorithmException e) {
            LOG.error("SSL上下文创建失败，由于" + e.getLocalizedMessage());
            e.printStackTrace();
        }
        return sslsf;
    }

    private String res(HttpRequestBase method) {
        HttpClientContext context = HttpClientContext.create();
        CloseableHttpResponse response = null;
        String content = RESPONSE_CONTENT;
        try {
            response = client.execute(method, context);//执行GET/POST请求
            HttpEntity entity = response.getEntity();//获取响应实体
            if (entity != null) {
                content = EntityUtils.toString(entity, Charset.forName("utf-8"));
                EntityUtils.consume(entity);
            }
        } catch (ConnectTimeoutException cte) {
            LOG.error("请求连接超时，由于 " + cte.getLocalizedMessage());
            cte.printStackTrace();
        } catch (SocketTimeoutException ste) {
            LOG.error("请求通信超时，由于 " + ste.getLocalizedMessage());
            ste.printStackTrace();
        } catch (ClientProtocolException cpe) {
            LOG.error("协议错误（比如构造HttpGet对象时传入协议不对(将'http'写成'htp')or响应内容不符合），由于 " + cpe.getLocalizedMessage());
            cpe.printStackTrace();
        } catch (IOException ie) {
            LOG.error("实体转换异常或者网络异常， 由于 " + ie.getLocalizedMessage());
            ie.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                LOG.error("响应关闭异常， 由于 " + e.getLocalizedMessage());
            }
            if (method != null) {
                method.releaseConnection();
            }
        }

        return content;
    }

    private String get(String url) {
        HttpGet get = new HttpGet(url);
        return res(get);
    }

    private String get(String url, String cookie) {
        HttpGet get = new HttpGet(url);
        if (StringUtils.isNotBlank(cookie))
            get.addHeader("cookie", cookie);
        return res(get);
    }

    private byte[] getAsByte(String url) {
        return get(url).getBytes();
    }

    private String getHeaders(String url, String cookie, String headerName) {
        HttpGet get = new HttpGet(url);
        if (StringUtils.isNotBlank(cookie))
            get.addHeader("cookie", cookie);
        res(get);
        Header[] headers = get.getHeaders(headerName);
        return headers == null ? null : headers.toString();
    }

    private String getWithRealHeader(String url) {
        HttpGet get = new HttpGet(url);
        get.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;");
        get.addHeader("Accept-Language", "zh-cn");
        get.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3");
        get.addHeader("Keep-Alive", "300");
        get.addHeader("Connection", "Keep-Alive");
        get.addHeader("Cache-Control", "no-cache");
        return res(get);
    }

    private String post(String url, Map<String, String> param, String cookie) {
        HttpPost post = new HttpPost(url);
        for (String key : param.keySet()) {
            String value = param.get(key);
            if (value != null)
                post.addHeader(key, value);
        }
        if (StringUtils.isNotBlank(cookie))
            post.addHeader("cookie", cookie);
        return res(post);
    }

    public String post(String url, String data) {
        HttpPost post = new HttpPost(url);
        if (StringUtils.isNotBlank(data))
            post.addHeader("Content-Type", "application/json");
        post.setEntity(new StringEntity(data, ContentType.APPLICATION_JSON));
        return res(post);
    }


    /**
     * 网络请求GET方法
     * @param url
     * @param querys
     * @param headers
     * @return
     * @throws Exception
     */
    public String get(String url, Map<String, String> querys, Map<String, String> headers) {
        try {
            //  querys
            if (querys != null && querys.size() > 0) {
                List<NameValuePair> querysList = new ArrayList<>();
                for (Map.Entry<String, String> entry : querys.entrySet()) {
                    querysList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                String queryString = EntityUtils.toString(new UrlEncodedFormEntity(querysList, Consts.UTF_8));
                url += ("?" + queryString);
            }
            //  url
            HttpGet get = new HttpGet(url);
            //  header
            if (headers != null && headers.size() > 0) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    get.addHeader(entry.getKey(), entry.getValue());
                }
            }
            return res(get);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return "请求失败";
    }

    /**
     * 网络请求POST方法
     *
     * @param url
     * @param querys
     * @param params
     * @param headers
     * @return
     * @throws Exception
     */
    public String post(String url, Map<String, String> querys, Map<String, String> params, Map<String, String> headers, String body) {
        try {
            //  querys
            if (querys != null && querys.size() > 0) {
                List<NameValuePair> querysList = new ArrayList<>();
                for (Map.Entry<String, String> entry : querys.entrySet()) {
                    querysList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                String queryString = EntityUtils.toString(new UrlEncodedFormEntity(querysList, Consts.UTF_8));
                url += ("?" + queryString);
            }
            //  url
            HttpPost post = new HttpPost(url);
            //  header
            if (headers != null && headers.size() > 0 ) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    post.addHeader(entry.getKey(), entry.getValue());
                }
            }
            if (StringUtils.isNotBlank(body)) {
                //  body
                post.setEntity(new StringEntity(body));
            }else {
                //  params
                if (params != null && params.size() > 0) {
                    List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
                    for (Map.Entry<String, String> entry : params.entrySet()) {
                        paramsList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                    }
                    post.setEntity(new UrlEncodedFormEntity(paramsList, "utf-8"));
                }
            }
            return res(post);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return "请求失败";
    }

}
